package com.mcr.reggie.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mcr.reggie.common.CustomException;
import com.mcr.reggie.dao.*;
import com.mcr.reggie.dto.OrdersDto;
import com.mcr.reggie.entity.*;
import com.mcr.reggie.service.*;
import com.mcr.reggie.utils.BaseContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Service
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements OrdersService {
    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private AddressBookMapper addressBookMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    @Transactional
    public void submit(Orders orders) {
        Long userId = BaseContext.getUser();
        LambdaQueryWrapper<ShoppingCart> shoppingCarQuery=new LambdaQueryWrapper<>();
        shoppingCarQuery.eq(ShoppingCart::getUserId,userId);
        List<ShoppingCart> shoppingCarts= (List<ShoppingCart>) redisTemplate.opsForValue().get("ShoppingCart:"+BaseContext.getUser());
        if(shoppingCarts==null||shoppingCarts.size()==0){
            throw new CustomException("购物车数据为空，程序出错");
        }
        User user = userMapper.selectById(userId);
        AddressBook addressBook = addressBookMapper.selectById(orders.getAddressBookId());
        if(addressBook==null){
            throw new CustomException("请求地址信息获取失败，请检查是否设定了默认地址");
        }
        //向当前订单表插入1条数据
        long orderId = IdWorker.getId();
        AtomicInteger amount=new AtomicInteger(0);
        /*AtomicInteger保持线程运算的原子性
            ①支持原子操作的Integer类;
            ②主要用于在高并发环境下的高效程序处理。使用非阻塞算法来实现并发控制;*/
        List<OrderDetail> orderDetails=shoppingCarts.stream().map((shoppingCart)->{
            //得出订单明细
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setOrderId(orderId);
            orderDetail.setNumber(shoppingCart.getNumber());
            orderDetail.setDishFlavor(shoppingCart.getDishFlavor());
            orderDetail.setDishId(shoppingCart.getDishId());
            orderDetail.setSetmealId(shoppingCart.getSetmealId());
            orderDetail.setName(shoppingCart.getName());
            orderDetail.setImage(shoppingCart.getImage());
            orderDetail.setAmount(shoppingCart.getAmount());
            //计算总金额
            amount.addAndGet(shoppingCart.getAmount().multiply(new BigDecimal(shoppingCart.getNumber())).intValue());
            //.multiply就是乘的意思
            return orderDetail;
        }).collect(Collectors.toList());
        orders.setId(orderId);
        orders.setOrderTime(LocalDateTime.now());
        orders.setCheckoutTime(LocalDateTime.now());
        orders.setStatus(2);
        orders.setAmount(new BigDecimal(amount.get()));//总金额
        orders.setUserId(userId);
        orders.setNumber(String.valueOf(orderId));
        orders.setUserName(user.getName());
        orders.setConsignee(addressBook.getConsignee());
        orders.setPhone(addressBook.getPhone());
        orders.setAddress((addressBook.getProvinceName() == null ? "" : addressBook.getProvinceName())
                + (addressBook.getCityName() == null ? "" : addressBook.getCityName())
                + (addressBook.getDistrictName() == null ? "" : addressBook.getDistrictName())
                + (addressBook.getDetail() == null ? "" : addressBook.getDetail()));
        ordersMapper.insert(orders);
        //向订单明细表插入若干条数据
        orderDetailService.saveBatch(orderDetails);
        //清空购物车
        redisTemplate.delete("ShoppingCart:"+BaseContext.getUser());
    }
    @Autowired
    private OrdersMapper ordersMapper;
    @Override
    public Page getPage(Integer page, Integer pageSize, String number, String beginTime,String endTime) {
        Page<Orders> ordersPage=new Page<>(page,pageSize);
        LambdaQueryWrapper<Orders> ordersQueryWrapper=new LambdaQueryWrapper<>();
        ordersQueryWrapper.like((number!=null),Orders::getNumber,number)
                .ge((beginTime!=null),Orders::getOrderTime,beginTime)
                .le((endTime!=null),Orders::getOrderTime,endTime)
                .orderByDesc(Orders::getOrderTime);
        ordersMapper.selectPage(ordersPage,ordersQueryWrapper);
        return ordersPage;
    }
    @Override
    public void updateStatus(Orders orders) {
        ordersMapper.updateById(orders);
    }

    @Override
    public Page<OrdersDto> getNewOrder(Integer page, Integer pageSize) {
        Page<Orders> ordersPage=new Page<>(page,pageSize);
        Page<OrdersDto> ordersDtoPage=new Page<>(page,pageSize);
        LambdaQueryWrapper<Orders> ordersQueryWrapper=new LambdaQueryWrapper<>();
        ordersQueryWrapper.orderByDesc(Orders::getOrderTime);
        ordersMapper.selectPage(ordersPage,ordersQueryWrapper);
        BeanUtils.copyProperties(ordersPage,ordersDtoPage,"records");
        List<OrdersDto> ordersDtoList = this.ordersDtoBOS(ordersPage.getRecords());
        ordersDtoPage.setRecords(ordersDtoList);
        return ordersDtoPage;
    }

    @Override
    public void submitAgain(Long id) {
        Orders orders = ordersMapper.selectById(id);
        LambdaQueryWrapper<OrderDetail> orderDetailQueryWrapper=new LambdaQueryWrapper<>();
        orderDetailQueryWrapper.eq(OrderDetail::getOrderId,id);
        List<OrderDetail> orderDetails = orderDetailMapper.selectList(orderDetailQueryWrapper);
        List<ShoppingCart> shoppingCartList=new ArrayList<>(orderDetails.size());
        for(OrderDetail orderDetail:orderDetails){
            ShoppingCart shoppingCart=new ShoppingCart();
            shoppingCart.setName(orderDetail.getName());
            shoppingCart.setImage(orderDetail.getImage());
            shoppingCart.setUserId(orders.getUserId());
            shoppingCart.setDishId(orderDetail.getDishId());
            shoppingCart.setSetmealId(orderDetail.getSetmealId());
            shoppingCart.setDishFlavor(orderDetail.getDishFlavor());
            shoppingCart.setNumber(orderDetail.getNumber());
            shoppingCart.setAmount(orderDetail.getAmount());
            shoppingCart.setCreateTime(LocalDateTime.now());
            shoppingCartList.add(shoppingCart);
        }
        redisTemplate.opsForValue().set("ShoppingCart:"+BaseContext.getUser(),shoppingCartList,30, TimeUnit.MINUTES);
    }

    //工具方法，list<order>--->>List<orders>
    private List<OrdersDto> ordersDtoBOS(List<Orders> ordersList){
        List<Long> orderIds=new ArrayList<>(ordersList.size());
        Map<Long,List<OrderDetail>> orderDetailMap=new HashMap<>();
        for(Orders orders:ordersList){
            orderIds.add(orders.getId());
            orderDetailMap.put(orders.getId(),new ArrayList<>());
        }
        LambdaQueryWrapper<OrderDetail> orderDetailQueryWrapper=new LambdaQueryWrapper<>();
        orderDetailQueryWrapper.in(OrderDetail::getOrderId,orderIds);
        List<OrderDetail> orderDetailList = orderDetailMapper.selectList(orderDetailQueryWrapper);
        for(OrderDetail orderDetail:orderDetailList){
            orderDetailMap.get(orderDetail.getOrderId()).add(orderDetail);
        }
        return ordersList.stream().map((orders)->{
            OrdersDto ordersDto=new OrdersDto();
            BeanUtils.copyProperties(orders,ordersDto);
            ordersDto.setOrderDetails(orderDetailMap.get(orders.getId()));
            return ordersDto;
        }).collect(Collectors.toList());
    }
}
